1 Gas Station Data Mapping

In order to review a selection of 500 random gas stations across the United States, the Gas Station - Point of Compromised data set was utilized. This data set includes 72798 records, 30 feature variables and one binary outcome variable, all utilized to capture extensive details about gas stations nationwide. Information from this dataset was read into the data frame named gas.raw

gas.raw <- read.csv("https://nlepera.github.io/sta553/w07_maps/data/POC.csv")
gas.raw <- gas.raw[order(-gas.raw$POCGAP), ]
str(gas.raw)
'data.frame':   72798 obs. of  32 variables:
 $ X                     : int  51008 60368 54411 40692 45554 51750 66537 17809 21600 44056 ...
 $ site_row_id           : chr  "1-1APFKEY" "1-203CEKO" "1-1APO2YR" "1-TJLO68" ...
 $ STATE                 : chr  "TX" "TX" "FL" "GA" ...
 $ county                : chr  "Harris" "Harris" "Orange" "Gwinnett" ...
 $ ADDRESS               : chr  "1900 S DAIRY ASHFORD RD" "3326 CANAL ST" "3048 ALOMA AVE" "1649 BEAVER RUIN RD" ...
 $ CITY                  : chr  "HOUSTON" "HOUSTON" "WINTER PARK" "NORCROSS" ...
 $ ycoord                : num  29.7 29.8 28.6 33.9 30.3 ...
 $ xcoord                : num  -95.6 -95.3 -81.3 -84.2 -81.6 ...
 $ SITE_DESCRIPTION      : chr  "Houston-Sugar Land-Baytown TX" "Houston-Sugar Land-Baytown TX" "Orlando-Kissimmee FL" "Atlanta-Sandy Springs-Marietta GA" ...
 $ service_or_fuel       : chr  "Fuel" "Fuel" "Fuel" "Fuel" ...
 $ diesel                : chr  "N" "Y" "N" "Y" ...
 $ twentyfour_hour_flag  : chr  "Y" "N" "N" "N" ...
 $ car_wash              : chr  "N" "N" "N" "N" ...
 $ truckstop_flag        : chr  "N" "N" "N" "Y" ...
 $ description           : chr  "URBAN" "URBAN" "URBAN" "URBAN" ...
 $ PUMP_TECH             : chr  "C" "V" "C" "O" ...
 $ POC                   : int  1 1 1 1 1 1 1 1 1 1 ...
 $ HIFCA                 : int  1 1 1 1 1 1 1 1 0 1 ...
 $ ZIPnew                : int  77077 77003 32792 30093 32216 94702 30324 76017 24093 32210 ...
 $ POCAGE                : int  240 240 239 237 236 236 235 234 234 234 ...
 $ POCGAP                : int  240 240 239 237 236 236 235 234 234 234 ...
 $ ZIPPOC                : int  1 1 1 1 1 1 1 1 1 3 ...
 $ HFG                   : int  1 1 1 0 1 0 1 0 0 1 ...
 $ MSA                   : int  3360 3360 5960 520 3600 5775 520 2800 0 3600 ...
 $ dist.to.poc           : num  3.43 3.74 7.48 12.85 2.88 ...
 $ cate.poc.density      : chr  "(5,Inf]" "(5,Inf]" "(5,Inf]" "(5,Inf]" ...
 $ cate.poc.age          : chr  "(0,15]" "(0,15]" "(0,15]" "(0,15]" ...
 $ cate.poc.age.20       : chr  "(0,15]" "(0,15]" "(0,15]" "(0,15]" ...
 $ cate.poc.intensity    : chr  "(5,Inf]" "(5,Inf]" "(0,5]" "(5,Inf]" ...
 $ cate.poc.intensity.tot: chr  "(8,Inf]" "(8,Inf]" "(8,Inf]" "(8,Inf]" ...
 $ MSA_POC               : int  1 1 1 1 0 0 1 1 0 0 ...
 $ MSA_POC.1             : int  1 1 1 1 0 0 1 1 0 0 ...

As the variable names are coded, a summary of each variable name and purpose is included below:


A breif glimpse at the first 500 observations of the data frame gas.raw is included below

DT::datatable(head(gas.raw, n=500), fillContainer = FALSE, options = list(pageLength = 10))

1.1 Prepping the Data

In order to properly view 500 gas stations across the United States, the data frame gas.raw was capped at the first 500 entries to create the new reduced data frame named gas.

Once truncated to 500 observations the data frame named gas was cleaned to remove all columns except the following: - State - County - Address - Zip Code - Length in Months between current and previous compromised cards - Longitude - Latitude

gas <- head(gas.raw, n=500) 
gas <- subset(gas, select = c(STATE, county, ADDRESS, ZIPnew, xcoord, ycoord, POCGAP ))
str(gas)
'data.frame':   500 obs. of  7 variables:
 $ STATE  : chr  "TX" "TX" "FL" "GA" ...
 $ county : chr  "Harris" "Harris" "Orange" "Gwinnett" ...
 $ ADDRESS: chr  "1900 S DAIRY ASHFORD RD" "3326 CANAL ST" "3048 ALOMA AVE" "1649 BEAVER RUIN RD" ...
 $ ZIPnew : int  77077 77003 32792 30093 32216 94702 30324 76017 24093 32210 ...
 $ xcoord : num  -95.6 -95.3 -81.3 -84.2 -81.6 ...
 $ ycoord : num  29.7 29.8 28.6 33.9 30.3 ...
 $ POCGAP : int  240 240 239 237 236 236 235 234 234 234 ...
DT::datatable(gas, fillContainer = FALSE, options = list(pageLength = 10))




1.2 Plotting the Data

g <- list(      scope = 'usa',
           projection = list(type = 'albers usa'),
             showland = TRUE,
            landcolor = ("lightgray"),
         subunitcolor = ("gray"),
         countrycolor = ("gray"),
         countrywidth = 0.5,
         subunitwidth = 0.5
       )

fig.gas <- plot_geo(gas, lat = ~ycoord, lon = ~xcoord, color =~POCGAP) %>% 
  add_markers( text = ~paste(ADDRESS, county, STATE, ZIPnew, paste("Time Since Last Compromised Card?:", POCGAP, "months"), 
                             sep = "<br>"),
               color = ~POCGAP,
               colors = 'RdYlBu',
               alpha = 0.85,
              hoverinfo = "text")   %>% 
  colorbar(title = "Time Since Last Compromised Card", y=0.85)  %>% 
  layout( title = 'Compromised Cards Utilized at a Random Sampling <br> of 500 Gas Stations Across the United States<br>', 
          geo = g )
  
fig.gas

2 Philadelphia Crime Data Analysis

In order to evaluate for any location trend related to fatality or prevelance of crime in the city of Philadelphia, the Philly Crime Data 2015-2024 dataset was utilized.

This data set includes 15520 records, of 18 variables, all utilized to capture extensive details about crimes committed in the city of Philadelphia. Information from this dataset was read into the data frame named crime.raw.

crime.raw <- read.csv("https://nlepera.github.io/sta553/w07_maps/data/PhillyCrimeSince2015.csv")
str(crime.raw)
'data.frame':   15520 obs. of  18 variables:
 $ dc_key          : chr  "2.02422E+11" "2.02426E+11" "2.02422E+11" "2.02422E+11" ...
 $ race            : chr  "Black (Non-Hispanic)" "Hispanic (Black or White)" "Black (Non-Hispanic)" "Black (Non-Hispanic)" ...
 $ sex             : chr  "Female" "Male" "Male" "Female" ...
 $ fatal           : chr  "Nonfatal" "Nonfatal" "Fatal" "Fatal" ...
 $ date            : chr  "3/3/2024 14:49" "3/1/2024 22:18" "2/29/2024 22:59" "2/29/2024 22:59" ...
 $ has_court_case  : chr  "No" "No" "No" "No" ...
 $ age             : int  20 58 49 38 19 31 29 38 44 44 ...
 $ street_name     : chr  "N COLORADO ST" "N FRANKLIN ST" "MOUNT PLEASANT DR" "MOUNT PLEASANT DR" ...
 $ block_number    : int  2500 2600 3700 3700 5600 5500 6400 4200 4200 4200 ...
 $ zip_code        : int  19132 19133 19121 19121 19131 19144 19142 19104 19104 19104 ...
 $ council_district: int  5 5 4 4 4 8 2 3 3 3 ...
 $ police_district : int  22 26 22 22 19 39 12 16 16 16 ...
 $ neighborhood    : chr  "Sharswood-Stanton" "Northern Liberties-West Kensington" "Park" "Park" ...
 $ house_district  : int  181 197 190 190 192 198 191 190 190 190 ...
 $ senate_district : int  3 3 7 7 7 3 8 7 7 7 ...
 $ school_catchment: chr  "Tanner G. Duckrey School" "John F. Hartranft School" "James G. Blaine School" "James G. Blaine School" ...
 $ lng             : num  -75.2 -75.1 -75.2 -75.2 -75.2 ...
 $ lat             : num  40 40 40 40 40 ...


A breif glimpse at the first 500 observations of the data frame crime.raw is included below

DT::datatable(head(crime.raw, n=500), fillContainer = FALSE, options = list(pageLength = 10))

As visibile in the summary table above, the year data required extraction from the date column.

crime.raw$year <- year(mdy_hm(crime.raw$date))
str(crime.raw)
'data.frame':   15520 obs. of  19 variables:
 $ dc_key          : chr  "2.02422E+11" "2.02426E+11" "2.02422E+11" "2.02422E+11" ...
 $ race            : chr  "Black (Non-Hispanic)" "Hispanic (Black or White)" "Black (Non-Hispanic)" "Black (Non-Hispanic)" ...
 $ sex             : chr  "Female" "Male" "Male" "Female" ...
 $ fatal           : chr  "Nonfatal" "Nonfatal" "Fatal" "Fatal" ...
 $ date            : chr  "3/3/2024 14:49" "3/1/2024 22:18" "2/29/2024 22:59" "2/29/2024 22:59" ...
 $ has_court_case  : chr  "No" "No" "No" "No" ...
 $ age             : int  20 58 49 38 19 31 29 38 44 44 ...
 $ street_name     : chr  "N COLORADO ST" "N FRANKLIN ST" "MOUNT PLEASANT DR" "MOUNT PLEASANT DR" ...
 $ block_number    : int  2500 2600 3700 3700 5600 5500 6400 4200 4200 4200 ...
 $ zip_code        : int  19132 19133 19121 19121 19131 19144 19142 19104 19104 19104 ...
 $ council_district: int  5 5 4 4 4 8 2 3 3 3 ...
 $ police_district : int  22 26 22 22 19 39 12 16 16 16 ...
 $ neighborhood    : chr  "Sharswood-Stanton" "Northern Liberties-West Kensington" "Park" "Park" ...
 $ house_district  : int  181 197 190 190 192 198 191 190 190 190 ...
 $ senate_district : int  3 3 7 7 7 3 8 7 7 7 ...
 $ school_catchment: chr  "Tanner G. Duckrey School" "John F. Hartranft School" "James G. Blaine School" "James G. Blaine School" ...
 $ lng             : num  -75.2 -75.1 -75.2 -75.2 -75.2 ...
 $ lat             : num  40 40 40 40 40 ...
 $ year            : num  2024 2024 2024 2024 2024 ...

2.1 Prepping the Data

In order to properly view a subeset of the Philadelphia crime data the data frame gas.raw was transformed to filter for crimes in the year 2023, with the following variables included:

  • Fatal
  • Sex
  • Block Number
  • Street Name
  • Zip Code
  • Neighborhood
  • Police District
  • Longitude
  • Latitude
crime.2023 <- crime.raw %>% 
  filter(year == 2023) %>% 
  subset (select = c(fatal, sex, block_number, street_name, zip_code, neighborhood, police_district, lng, lat))
str(crime.2023)
'data.frame':   1666 obs. of  9 variables:
 $ fatal          : chr  "Nonfatal" "Fatal" "Nonfatal" "Nonfatal" ...
 $ sex            : chr  "Male" "Male" "Male" "Male" ...
 $ block_number   : int  5500 800 5000 0 1700 1000 3800 8200 3000 2800 ...
 $ street_name    : chr  "OLD YORK RD" "E MADISON ST" "COTTMAN AVE" "W CHELTEN AVE" ...
 $ zip_code       : int  19141 19134 19136 19144 19140 19104 19104 19153 19134 19133 ...
 $ neighborhood   : chr  "Logan" "Upper Kensington" "Wissinoming-Tacony" "Germantown" ...
 $ police_district: int  35 24 15 14 39 16 16 12 24 25 ...
 $ lng            : num  -75.1 -75.1 -75 -75.2 -75.2 ...
 $ lat            : num  40 40 40 40 40 ...
DT::datatable(crime.2023, fillContainer = FALSE, options = list(pageLength = 10))




2.2 Plotting the Data

Below you will find an interactive map outlining the crimes in Philadelphia throughout 2023. Crimes are sorted by fatal/non-fatal using color. Click on any data point to see additional information regarding the crime location.

fatal.color <- rep("navy")
fatal.color[which(crime.2023$fatal=="Fatal")] <- "Orange"
fatal.color[which(crime.2023$fatal=="Nonfatal")] <- "Blue"

label.msg <- paste(paste("Fatal?:", crime.2023$fatal),    
                   paste("Sex:", crime.2023$sex),
                   paste("Address:", crime.2023$block_number, crime.2023$street_name))

leaflet(crime.2023) %>% 
  addTiles() %>% 
  addProviderTiles("Esri.WorldGrayCanvas") %>%
  addCircleMarkers(
            ~lng, 
            ~lat,
            color = fatal.color,
            stroke = FALSE, 
            fillOpacity = 0.4,
            label = ~label.msg) %>% 
  addTiles("2023 Crimes in Philadelphia") %>% 
 addLegend(position = "bottomright", 
            colors = c("blue", "orange"),
            labels= c("Non-Fatal", "Fatal"),
            title= "Victim Gender",
            opacity = 0.4) 


LS0tDQp0aXRsZTogIk1hcHMsIE1hcHMsIGFuZCBNb3JlIE1hcHMiDQphdXRob3I6ICJOYXRhbGllIExlUGVyYSINCmRhdGU6ICJXZXN0IENoZXN0ZXIgVW5pdmVyc2l0eSA8YnI+U1RBIDUwMzogRGF0YSBWaXN1YWxpemF0aW9uIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIHRvY19mbG9hdDogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBzbW9vdGhfc2Nyb2xsOiB0cnVlDQogICAgdGhlbWU6IHJlYWRhYmxlDQotLS0NCg0KYGBgez1odG1sfQ0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4NCg0KZGl2I1RPQyBsaSB7DQogICAgbGlzdC1zdHlsZTpub25lOw0KICAgIGJhY2tncm91bmQtY29sb3I6bGlnaHRncmF5Ow0KICAgIGJhY2tncm91bmQtaW1hZ2U6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLXJlcGVhdDpub25lOw0KICAgIGJhY2tncm91bmQtcG9zaXRpb246MDsNCiAgICBmb250LWZhbWlseTogQXJpYWwsIEhlbHZldGljYSwgc2Fucy1zZXJpZjsNCiAgICBjb2xvcjogIzc4MGMwYzsNCn0NCg0KLyogbW91c2Ugb3ZlciBsaW5rICovDQpkaXYjVE9DIGE6aG92ZXIgew0KICBjb2xvcjogcmVkOw0KfQ0KDQovKiB1bnZpc2l0ZWQgbGluayAqLw0KZGl2I1RPQyBhOmxpbmsgew0KICBjb2xvcjogYmx1ZTsNCn0NCg0KDQoNCmgxLnRpdGxlIHsNCiAgZm9udC1zaXplOiAyNHB4Ow0KICBjb2xvcjogRGFya2JsdWU7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCiAgZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7DQogIGZvbnQtdmFyaWFudC1jYXBzOiBub3JtYWw7DQp9DQpoNC5zdWJ0aXRsZSB7DQogIGZvbnQtc2l6ZTogMThweDsNCiAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogIGNvbG9yOiBEYXJrUmVkOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQpoNC5hdXRob3IgeyANCiAgICBmb250LXNpemU6IDE4cHg7DQogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICBjb2xvcjogRGFya1JlZDsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KaDQuZGF0ZSB7IA0KICBmb250LXNpemU6IDE4cHg7DQogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICBjb2xvcjogRGFya0JsdWU7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmgxIHsNCiAgICBmb250LXNpemU6IDI0cHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KaDIgew0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCmgzIHsgDQogICAgZm9udC1zaXplOiAxNXB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmg0IHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KLyogdW52aXNpdGVkIGxpbmsgKi8NCmE6bGluayB7DQogIGNvbG9yOiBncmVlbjsNCn0NCg0KLyogdmlzaXRlZCBsaW5rICovDQphOnZpc2l0ZWQgew0KICBjb2xvcjogZ3JlZW47DQp9DQoNCi8qIG1vdXNlIG92ZXIgbGluayAqLw0KYTpob3ZlciB7DQogIGNvbG9yOiByZWQ7DQp9DQoNCi8qIHNlbGVjdGVkIGxpbmsgKi8NCmE6YWN0aXZlIHsNCiAgY29sb3I6IHllbGxvdzsNCn0NCg0KPC9zdHlsZT4NCmBgYA0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQojIGNvZGUgY2h1bmsgc3BlY2lmaWVzIHdoZXRoZXIgdGhlIFIgY29kZSwgd2FybmluZ3MsIGFuZCBvdXRwdXQgDQojIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG91dHB1dCBmaWxlcy4NCm9wdGlvbnMocmVwb3MgPSBsaXN0KENSQU49Imh0dHA6Ly9jcmFuLnJzdHVkaW8uY29tLyIpKQ0KaWYgKCFyZXF1aXJlKCJ0aWR5dmVyc2UiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikNCiAgIGxpYnJhcnkodGlkeXZlcnNlKQ0KfQ0KaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpDQogICBsaWJyYXJ5KGtuaXRyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJjb3dwbG90IikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImNvd3Bsb3QiKQ0KICAgbGlicmFyeShjb3dwbG90KQ0KfQ0KaWYgKCFyZXF1aXJlKCJsYXRleDJleHAiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygibGF0ZXgyZXhwIikNCiAgIGxpYnJhcnkobGF0ZXgyZXhwKQ0KfQ0KaWYgKCFyZXF1aXJlKCJwbG90bHkiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygicGxvdGx5IikNCiAgIGxpYnJhcnkocGxvdGx5KQ0KfQ0KaWYgKCFyZXF1aXJlKCJnYXBtaW5kZXIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygiZ2FwbWluZGVyIikNCiAgIGxpYnJhcnkoZ2FwbWluZGVyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJwbmciKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoInBuZyIpICAgICAgICAgICAgICMgSW5zdGFsbCBwbmcgcGFja2FnZQ0KICAgIGxpYnJhcnkoInBuZyIpDQp9DQppZiAoIXJlcXVpcmUoIlJDdXJsIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJSQ3VybCIpICAgICAgICAgICAjIEluc3RhbGwgUkN1cmwgcGFja2FnZQ0KICAgIGxpYnJhcnkoIlJDdXJsIikNCn0NCmlmICghcmVxdWlyZSgiY29sb3VycGlja2VyIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJjb2xvdXJwaWNrZXIiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiY29sb3VycGlja2VyIikNCn0NCmlmICghcmVxdWlyZSgiZ2lmc2tpIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJnaWZza2kiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiZ2lmc2tpIikNCn0NCmlmICghcmVxdWlyZSgibWFnaWNrIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJtYWdpY2siKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgibWFnaWNrIikNCn0NCmlmICghcmVxdWlyZSgiZ3JEZXZpY2VzIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJnckRldmljZXMiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiZ3JEZXZpY2VzIikNCn0NCiMjIyBnZ3Bsb3QgYW5kIGV4dGVuc2lvbnMNCmlmICghcmVxdWlyZSgiZ2dwbG90MiIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJnZ3Bsb3QyIikNCn0NCmlmICghcmVxdWlyZSgiZ2dhbmltYXRlIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJnZ2FuaW1hdGUiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiZ2dhbmltYXRlIikNCn0NCmlmICghcmVxdWlyZSgiZ2dyaWRnZXMiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImdncmlkZ2VzIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImdncmlkZ2VzIikNCn0NCmlmICghcmVxdWlyZSgiZ3JhcGhpY3MiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImdyYXBoaWNzIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImdyYXBoaWNzIikNCn0NCmlmICghcmVxdWlyZSgib3Blbnhsc3giKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoIm9wZW54bHN4IikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoIm9wZW54bHN4IikNCn0NCg0KaWYgKCFyZXF1aXJlKCJsdWJyaWRhdGUiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImx1YnJpZGF0ZSIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJsdWJyaWRhdGUiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJyanNvbiIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygicmpzb24iKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgicmpzb24iKQ0KfQ0KaWYgKCFyZXF1aXJlKCJsZWFmbGV0IikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJsZWFmbGV0IikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImxlYWZsZXQiKQ0KfQ0KDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwgICANCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHQgPSBUUlVFLCAgIA0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkEpDQpgYGANClwNCg0KIyBHYXMgU3RhdGlvbiBEYXRhIE1hcHBpbmcNCkluIG9yZGVyIHRvIHJldmlldyBhIHNlbGVjdGlvbiBvZiA1MDAgcmFuZG9tIGdhcyBzdGF0aW9ucyBhY3Jvc3MgdGhlIFVuaXRlZCBTdGF0ZXMsIHRoZSBHYXMgU3RhdGlvbiAtIFBvaW50IG9mIENvbXByb21pc2VkIGRhdGEgc2V0IHdhcyB1dGlsaXplZC4gIFRoaXMgZGF0YSBzZXQgaW5jbHVkZXMgNzI3OTggcmVjb3JkcywgMzAgZmVhdHVyZSB2YXJpYWJsZXMgYW5kIG9uZSBiaW5hcnkgb3V0Y29tZSB2YXJpYWJsZSwgYWxsIHV0aWxpemVkIHRvIGNhcHR1cmUgZXh0ZW5zaXZlIGRldGFpbHMgYWJvdXQgZ2FzIHN0YXRpb25zIG5hdGlvbndpZGUuICBJbmZvcm1hdGlvbiBmcm9tIHRoaXMgZGF0YXNldCB3YXMgcmVhZCBpbnRvIHRoZSBkYXRhIGZyYW1lIG5hbWVkIDxmb250IGNvbG9yID0gInB1cnBsZSI+PGk+Z2FzLnJhdzxpPjwvZm9udD4NCg0KDQpgYGB7cn0NCmdhcy5yYXcgPC0gcmVhZC5jc3YoImh0dHBzOi8vbmxlcGVyYS5naXRodWIuaW8vc3RhNTUzL3cwN19tYXBzL2RhdGEvUE9DLmNzdiIpDQpnYXMucmF3IDwtIGdhcy5yYXdbb3JkZXIoLWdhcy5yYXckUE9DR0FQKSwgXQ0KYGBgDQoNCmBgYHtyIGVjaG8gPSBUUlVFfQ0Kc3RyKGdhcy5yYXcpDQpgYGANCg0KQXMgdGhlIHZhcmlhYmxlIG5hbWVzIGFyZSBjb2RlZCwgYSBzdW1tYXJ5IG9mIGVhY2ggdmFyaWFibGUgbmFtZSBhbmQgcHVycG9zZSBpcyBpbmNsdWRlZCBiZWxvdzoNCg0KDQo8Y2VudGVyPjxkaXYgY2xhc3M9J3dyYXAnPg0KPGlmcmFtZSBzcmM9Imh0dHBzOi8vbmxlcGVyYS5naXRodWIuaW8vc3RhNTUzL3cwN19tYXBzL2RhdGEvZ2FzX3ZhcmlhYmxlX2RlZi5wZGYiIHRpdGxlPSJWYXJpYWJsZSBEZWZpbml0aW9ucyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSI+PC9pZnJhbWU+DQo8L2Rpdj48L2NlbnRlcj4NCg0KPGJyPg0KQSBicmVpZiBnbGltcHNlIGF0IHRoZSBmaXJzdCA1MDAgb2JzZXJ2YXRpb25zIG9mIHRoZSBkYXRhIGZyYW1lIDxmb250IGNvbG9yID0gInB1cnBsZSI+PGk+Z2FzLnJhdzxpPjwvZm9udD4gaXMgaW5jbHVkZWQgYmVsb3cNCjxicj4NCg0KDQpgYGB7cn0NCkRUOjpkYXRhdGFibGUoaGVhZChnYXMucmF3LCBuPTUwMCksIGZpbGxDb250YWluZXIgPSBGQUxTRSwgb3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDEwKSkNCmBgYA0KDQoNCiMjIFByZXBwaW5nIHRoZSBEYXRhDQoNCkluIG9yZGVyIHRvIHByb3Blcmx5IHZpZXcgNTAwIGdhcyBzdGF0aW9ucyBhY3Jvc3MgdGhlIFVuaXRlZCBTdGF0ZXMsIHRoZSBkYXRhIGZyYW1lIDxmb250IGNvbG9yID0gInB1cnBsZSI+PGk+Z2FzLnJhdzxpPjwvZm9udD4gd2FzIGNhcHBlZCBhdCB0aGUgZmlyc3QgNTAwIGVudHJpZXMgdG8gY3JlYXRlIHRoZSBuZXcgcmVkdWNlZCBkYXRhIGZyYW1lIG5hbWVkIDxmb250IGNvbG9yID0gInB1cnBsZSI+PGk+Z2FzPGk+PC9mb250Pi4NCg0KT25jZSB0cnVuY2F0ZWQgdG8gNTAwIG9ic2VydmF0aW9ucyB0aGUgZGF0YSBmcmFtZSBuYW1lZCA8Zm9udCBjb2xvciA9ICJwdXJwbGUiPjxpPmdhczxpPjwvZm9udD4gd2FzIGNsZWFuZWQgdG8gcmVtb3ZlIGFsbCBjb2x1bW5zIGV4Y2VwdCB0aGUgZm9sbG93aW5nOg0KLSAgIFN0YXRlDQotICAgQ291bnR5DQotICAgQWRkcmVzcw0KLSAgIFppcCBDb2RlDQotICAgTGVuZ3RoIGluIE1vbnRocyBiZXR3ZWVuIGN1cnJlbnQgYW5kIHByZXZpb3VzIGNvbXByb21pc2VkIGNhcmRzDQotICAgTG9uZ2l0dWRlDQotICAgTGF0aXR1ZGUNCg0KDQpgYGB7cn0NCmdhcyA8LSBoZWFkKGdhcy5yYXcsIG49NTAwKSANCmdhcyA8LSBzdWJzZXQoZ2FzLCBzZWxlY3QgPSBjKFNUQVRFLCBjb3VudHksIEFERFJFU1MsIFpJUG5ldywgeGNvb3JkLCB5Y29vcmQsIFBPQ0dBUCApKQ0KYGBgDQoNCmBgYHtyIGVjaG8gPSBUUlVFfQ0Kc3RyKGdhcykNCmBgYA0KYGBge3J9DQpEVDo6ZGF0YXRhYmxlKGdhcywgZmlsbENvbnRhaW5lciA9IEZBTFNFLCBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gMTApKQ0KYGBgDQo8YnI+DQo8YnI+DQo8YnI+DQoNCiMjIFBsb3R0aW5nIHRoZSBEYXRhDQoNCmBgYHtyfQ0KZyA8LSBsaXN0KCAgICAgIHNjb3BlID0gJ3VzYScsDQogICAgICAgICAgIHByb2plY3Rpb24gPSBsaXN0KHR5cGUgPSAnYWxiZXJzIHVzYScpLA0KICAgICAgICAgICAgIHNob3dsYW5kID0gVFJVRSwNCiAgICAgICAgICAgIGxhbmRjb2xvciA9ICgibGlnaHRncmF5IiksDQogICAgICAgICBzdWJ1bml0Y29sb3IgPSAoImdyYXkiKSwNCiAgICAgICAgIGNvdW50cnljb2xvciA9ICgiZ3JheSIpLA0KICAgICAgICAgY291bnRyeXdpZHRoID0gMC41LA0KICAgICAgICAgc3VidW5pdHdpZHRoID0gMC41DQogICAgICAgKQ0KDQpmaWcuZ2FzIDwtIHBsb3RfZ2VvKGdhcywgbGF0ID0gfnljb29yZCwgbG9uID0gfnhjb29yZCwgY29sb3IgPX5QT0NHQVApICU+JSANCiAgYWRkX21hcmtlcnMoIHRleHQgPSB+cGFzdGUoQUREUkVTUywgY291bnR5LCBTVEFURSwgWklQbmV3LCBwYXN0ZSgiVGltZSBTaW5jZSBMYXN0IENvbXByb21pc2VkIENhcmQ/OiIsIFBPQ0dBUCwgIm1vbnRocyIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VwID0gIjxicj4iKSwNCiAgICAgICAgICAgICAgIGNvbG9yID0gflBPQ0dBUCwNCiAgICAgICAgICAgICAgIGNvbG9ycyA9ICdSZFlsQnUnLA0KICAgICAgICAgICAgICAgYWxwaGEgPSAwLjg1LA0KICAgICAgICAgICAgICBob3ZlcmluZm8gPSAidGV4dCIpICAgJT4lIA0KICBjb2xvcmJhcih0aXRsZSA9ICJUaW1lIFNpbmNlIExhc3QgQ29tcHJvbWlzZWQgQ2FyZCIsIHk9MC44NSkgICU+JSANCiAgbGF5b3V0KCB0aXRsZSA9ICdDb21wcm9taXNlZCBDYXJkcyBVdGlsaXplZCBhdCBhIFJhbmRvbSBTYW1wbGluZyA8YnI+IG9mIDUwMCBHYXMgU3RhdGlvbnMgQWNyb3NzIHRoZSBVbml0ZWQgU3RhdGVzPGJyPicsIA0KICAgICAgICAgIGdlbyA9IGcgKQ0KICANCmZpZy5nYXMNCmBgYA0KDQoNCiMgUGhpbGFkZWxwaGlhIENyaW1lIERhdGEgQW5hbHlzaXMNCg0KSW4gb3JkZXIgdG8gZXZhbHVhdGUgZm9yIGFueSBsb2NhdGlvbiB0cmVuZCByZWxhdGVkIHRvIGZhdGFsaXR5IG9yIHByZXZlbGFuY2Ugb2YgY3JpbWUgaW4gdGhlIGNpdHkgb2YgUGhpbGFkZWxwaGlhLCB0aGUgUGhpbGx5IENyaW1lIERhdGEgMjAxNS0yMDI0IGRhdGFzZXQgd2FzIHV0aWxpemVkLg0KDQogIFRoaXMgZGF0YSBzZXQgaW5jbHVkZXMgMTU1MjAgcmVjb3Jkcywgb2YgMTggdmFyaWFibGVzLCBhbGwgdXRpbGl6ZWQgdG8gY2FwdHVyZSBleHRlbnNpdmUgZGV0YWlscyBhYm91dCBjcmltZXMgY29tbWl0dGVkIGluIHRoZSBjaXR5IG9mIFBoaWxhZGVscGhpYS4gIEluZm9ybWF0aW9uIGZyb20gdGhpcyBkYXRhc2V0IHdhcyByZWFkIGludG8gdGhlIGRhdGEgZnJhbWUgbmFtZWQgPGZvbnQgY29sb3IgPSAicHVycGxlIj48aT5jcmltZS5yYXc8aT48L2ZvbnQ+Lg0KYGBge3J9DQpjcmltZS5yYXcgPC0gcmVhZC5jc3YoImh0dHBzOi8vbmxlcGVyYS5naXRodWIuaW8vc3RhNTUzL3cwN19tYXBzL2RhdGEvUGhpbGx5Q3JpbWVTaW5jZTIwMTUuY3N2IikNCmBgYA0KDQpgYGB7ciBlY2hvID0gVFJVRX0NCnN0cihjcmltZS5yYXcpDQpgYGANCg0KPGJyPg0KQSBicmVpZiBnbGltcHNlIGF0IHRoZSBmaXJzdCA1MDAgb2JzZXJ2YXRpb25zIG9mIHRoZSBkYXRhIGZyYW1lIDxmb250IGNvbG9yID0gInB1cnBsZSI+PGk+Y3JpbWUucmF3PGk+PC9mb250PiBpcyBpbmNsdWRlZCBiZWxvdw0KPGJyPg0KDQoNCmBgYHtyfQ0KRFQ6OmRhdGF0YWJsZShoZWFkKGNyaW1lLnJhdywgbj01MDApLCBmaWxsQ29udGFpbmVyID0gRkFMU0UsIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSAxMCkpDQpgYGANCg0KDQpBcyB2aXNpYmlsZSBpbiB0aGUgc3VtbWFyeSB0YWJsZSBhYm92ZSwgdGhlIHllYXIgZGF0YSByZXF1aXJlZCBleHRyYWN0aW9uIGZyb20gdGhlIGRhdGUgY29sdW1uLiAgDQoNCmBgYHtyfQ0KY3JpbWUucmF3JHllYXIgPC0geWVhcihtZHlfaG0oY3JpbWUucmF3JGRhdGUpKQ0KYGBgDQoNCmBgYHtyIGVjaG89VFJVRX0NCnN0cihjcmltZS5yYXcpDQpgYGANCg0KDQojIyBQcmVwcGluZyB0aGUgRGF0YQ0KSW4gb3JkZXIgdG8gcHJvcGVybHkgdmlldyBhIHN1YmVzZXQgb2YgdGhlIFBoaWxhZGVscGhpYSBjcmltZSBkYXRhIHRoZSBkYXRhIGZyYW1lIDxmb250IGNvbG9yID0gInB1cnBsZSI+PGk+Z2FzLnJhdzxpPjwvZm9udD4gd2FzIHRyYW5zZm9ybWVkIHRvIGZpbHRlciBmb3IgY3JpbWVzIGluIHRoZSB5ZWFyIDIwMjMsIHdpdGggdGhlIGZvbGxvd2luZyB2YXJpYWJsZXMgaW5jbHVkZWQ6DQoNCi0gICBGYXRhbA0KLSAgIFNleA0KLSAgIEJsb2NrIE51bWJlcg0KLSAgIFN0cmVldCBOYW1lDQotICAgWmlwIENvZGUNCi0gICBOZWlnaGJvcmhvb2QNCi0gICBQb2xpY2UgRGlzdHJpY3QNCi0gICBMb25naXR1ZGUNCi0gICBMYXRpdHVkZQ0KDQpgYGB7cn0NCmNyaW1lLjIwMjMgPC0gY3JpbWUucmF3ICU+JSANCiAgZmlsdGVyKHllYXIgPT0gMjAyMykgJT4lIA0KICBzdWJzZXQgKHNlbGVjdCA9IGMoZmF0YWwsIHNleCwgYmxvY2tfbnVtYmVyLCBzdHJlZXRfbmFtZSwgemlwX2NvZGUsIG5laWdoYm9yaG9vZCwgcG9saWNlX2Rpc3RyaWN0LCBsbmcsIGxhdCkpDQpgYGANCg0KDQpgYGB7ciBlY2hvPVRSVUV9DQpzdHIoY3JpbWUuMjAyMykNCmBgYA0KDQpgYGB7cn0NCkRUOjpkYXRhdGFibGUoY3JpbWUuMjAyMywgZmlsbENvbnRhaW5lciA9IEZBTFNFLCBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gMTApKQ0KYGBgDQoNCjxicj4NCjxicj4NCjxicj4NCg0KIyMgUGxvdHRpbmcgdGhlIERhdGENCg0KQmVsb3cgeW91IHdpbGwgZmluZCBhbiBpbnRlcmFjdGl2ZSBtYXAgb3V0bGluaW5nIHRoZSBjcmltZXMgaW4gUGhpbGFkZWxwaGlhIHRocm91Z2hvdXQgMjAyMy4gIENyaW1lcyBhcmUgc29ydGVkIGJ5IGZhdGFsL25vbi1mYXRhbCB1c2luZyBjb2xvci4gIENsaWNrIG9uIGFueSBkYXRhIHBvaW50IHRvIHNlZSBhZGRpdGlvbmFsIGluZm9ybWF0aW9uIHJlZ2FyZGluZyB0aGUgY3JpbWUgbG9jYXRpb24uDQo8YnI+DQoNCmBgYHtyfQ0KZmF0YWwuY29sb3IgPC0gcmVwKCJuYXZ5IikNCmZhdGFsLmNvbG9yW3doaWNoKGNyaW1lLjIwMjMkZmF0YWw9PSJGYXRhbCIpXSA8LSAiT3JhbmdlIg0KZmF0YWwuY29sb3Jbd2hpY2goY3JpbWUuMjAyMyRmYXRhbD09Ik5vbmZhdGFsIildIDwtICJCbHVlIg0KDQpsYWJlbC5tc2cgPC0gcGFzdGUocGFzdGUoIkZhdGFsPzoiLCBjcmltZS4yMDIzJGZhdGFsKSwgICAgDQogICAgICAgICAgICAgICAgICAgcGFzdGUoIlNleDoiLCBjcmltZS4yMDIzJHNleCksDQogICAgICAgICAgICAgICAgICAgcGFzdGUoIkFkZHJlc3M6IiwgY3JpbWUuMjAyMyRibG9ja19udW1iZXIsIGNyaW1lLjIwMjMkc3RyZWV0X25hbWUpKQ0KDQpsZWFmbGV0KGNyaW1lLjIwMjMpICU+JSANCiAgYWRkVGlsZXMoKSAlPiUgDQogIGFkZFByb3ZpZGVyVGlsZXMoIkVzcmkuV29ybGRHcmF5Q2FudmFzIikgJT4lDQogIGFkZENpcmNsZU1hcmtlcnMoDQogICAgICAgICAgICB+bG5nLCANCiAgICAgICAgICAgIH5sYXQsDQogICAgICAgICAgICBjb2xvciA9IGZhdGFsLmNvbG9yLA0KICAgICAgICAgICAgc3Ryb2tlID0gRkFMU0UsIA0KICAgICAgICAgICAgZmlsbE9wYWNpdHkgPSAwLjQsDQogICAgICAgICAgICBsYWJlbCA9IH5sYWJlbC5tc2cpICU+JSANCiAgYWRkVGlsZXMoIjIwMjMgQ3JpbWVzIGluIFBoaWxhZGVscGhpYSIpICU+JSANCiBhZGRMZWdlbmQocG9zaXRpb24gPSAiYm90dG9tcmlnaHQiLCANCiAgICAgICAgICAgIGNvbG9ycyA9IGMoImJsdWUiLCAib3JhbmdlIiksDQogICAgICAgICAgICBsYWJlbHM9IGMoIk5vbi1GYXRhbCIsICJGYXRhbCIpLA0KICAgICAgICAgICAgdGl0bGU9ICJWaWN0aW0gR2VuZGVyIiwNCiAgICAgICAgICAgIG9wYWNpdHkgPSAwLjQpIA0KDQoNCmBgYA0KDQpc